package main

import "fmt"

func main() {

	// 数组 --值类型
	//testArr()

	// 切片 --引用类型
	//testSlic()

	// map --引用类型
	//testMap()

	// 指针
	//testPoint()

	// 结构体 --值类型
	testStruct()
}

func testStruct() {
	var user User
	user.name = "sali"
	user.age = 18
	user.sex = "male"
	fmt.Println(user)

	user2 := User{}
	user2.name = "sali2"
	user2.age = 19
	user2.sex = "male"
	fmt.Println(user2)

	user3 := User{
		name: "sali3",
		age:  2,
		sex:  "male",
	}
	fmt.Println(user3)

	user4 := User{"sali4", 3, "male"}
	fmt.Println(user4)

	fmt.Println("\n------------")

	// 结构体是值类型的
	fmt.Println(user)
	user22 := user
	user22.name = "zhangsan"
	fmt.Println(user)
	fmt.Println(user22)

	// 结构体指针实现深拷贝
	var user33 *User
	user33 = &user
	(*user33).name = "salisalisali"
	fmt.Println(user)
	fmt.Println(*user33)

	// new获取到的也是结构体
	user44 := new(User)
	fmt.Printf("%T\n", user44)
	(*user44).name = "sali123"
	user44.age = 123
	fmt.Println(*user44)

	fmt.Println("\n------------")

	// 匿名结构体
	s22 := struct {
		name string
		age  int
	}{
		name: "zhangsan",
		age:  3,
	}
	fmt.Println(s22.name)

	// 匿名字段
	user55 := new(Teacher)
	user55.string = "zz"
	fmt.Println(*user55)

	fmt.Println("\n------------")

	// 结构体嵌套
	var person = Person{}
	person.name = "sali"
	person.age = 18
	person.addr = Address{
		city:  "guangzhou",
		state: "中国",
	}
	fmt.Println(person.addr)
	fmt.Println(person.name)
}

// 小写字母开头的结构体无法挎包
type Person struct {
	name string
	age  int
	addr Address
}
type Address struct {
	city, state string
}

type User struct {
	name string
	age  int
	sex  string
}

type Teacher struct {
	string
	int
}

func testPoint() {
	// 指针是存储另一个变量内存地址的变量
	var a = 10
	var b = &a
	fmt.Println("变量a的值:", a)
	fmt.Println("变量a的内存地址值:", &a)
	fmt.Println("变量b的值:", b)
	fmt.Println("变量b指向的内存地址中存储的值：", *b)
	*b = 20
	fmt.Println("变量a的值:", a)

	// 数组指针
	arr1 := [4]int{10, 20, 30, 40}
	fmt.Printf("arr1的地址:%p \n", &arr1)
	var p1 *[4]int
	p1 = &arr1
	fmt.Printf("p1->地址:%p \n", p1)
	fmt.Printf("p1地址:%p \n", &p1)
	fmt.Println("p1->地址->值: ", *p1)
	(*p1)[0] = 100
	fmt.Println(arr1)
	fmt.Println(*p1)
	// 简化写法
	p1[0] = 200
	fmt.Println(arr1)
	fmt.Println(*p1)

	fmt.Println("\n------------")

	// 指针数组
	aa := 1
	bb := 2
	cc := 3
	arr2 := [3]*int{&aa, &bb, &cc}
	fmt.Println(arr2)
	*arr2[0] = 500
	fmt.Println(aa)
	aa = 100
	fmt.Println(*arr2[0])

	fmt.Println("\n------------")

	// 指针函数
	ptr := f11()
	fmt.Printf("ptr的类型：%T\n", ptr)
	fmt.Println("ptr的地址：", &ptr)
	fmt.Println("ptr->地址的值:", *ptr)
	fmt.Println((*ptr)[0])
	fmt.Println(ptr[0])

	aaa := 10
	fmt.Println("aaa=", aaa)
	f22(&aaa)
	fmt.Println("aaa=", aaa)
}

func f22(ptr *int) {
	fmt.Println("ptr:", ptr)
	fmt.Println("*ptr:", *ptr)
	*ptr = 100
}

func f11() *[4]int {
	arr := [4]int{10, 20, 30, 40}
	return &arr
}

func testMap() {
	// map定义
	var map1 map[int]string
	var map2 = make(map[string]string)
	var map3 = map[string]int{"Go": 100, "Java": 80, "C": 60}
	map3["xixi"] = 1
	fmt.Println(map3)
	fmt.Println(map1 == nil)
	fmt.Println(map2 == nil) // 这里是false，初始化是[]

	fmt.Println("\n------------")

	// map赋值
	var map11 map[int]string
	map11 = make(map[int]string)
	map11[1] = "sali1"
	map11[2] = "sali2"
	map11[3] = "sali3"
	fmt.Println(map11[1])
	fmt.Println(map11[5])

	// 可通过ok-idiom来判断kv是否存在
	value, ok := map11[2]
	if ok {
		fmt.Println("map key存在, value:", value)
	} else {
		fmt.Println("map key不存在")
	}

	// 修改数据
	map11[1] = "hahahaha"
	fmt.Println(map11)
	// 删除数据
	delete(map11, 1)
	fmt.Println(map11)
	// 如果key不存在则新增，存在则修改
	map11[10] = "sali10"
	fmt.Println(map11)

	// 无序遍历
	for k := range map11 {
		fmt.Println(k, map11[k])
	}

	// map是引用类型
	map22 := map11
	map22[2] = "sali22"
	fmt.Println(map11)

	fmt.Println("\n------------")
	// 小练习
	user1 := make(map[string]string)
	user1["name"] = "sali1"
	user1["age"] = "age1"
	user1["sex"] = "male"
	user1["addr"] = "addr1"

	user2 := map[string]string{"name": "sali2", "age": "age2", "sex": "male", "addr": "addr2"}

	userData := make([]map[string]string, 0, 3)
	userData = append(userData, user1)
	userData = append(userData, user2)
	fmt.Println(userData)
	for _, v := range userData {
		fmt.Printf("name:%s\n", v["name"])
		fmt.Printf("age:%s\n", v["age"])
		fmt.Printf("sex:%s\n", v["sex"])
		fmt.Printf("addr:%s\n", v["addr"])
		fmt.Println("--")
	}
}

func testSlic() {
	// 切片
	s2 := []int{1, 2, 3, 4, 5}
	fmt.Println(s2)
	// make创建切片
	s3 := make([]int, 5, 10)
	fmt.Println(s3)
	fmt.Println("长度：", len(s3))
	fmt.Println("容量：", cap(s3))
	// s3[6] = 200 // index out of range[6] with length 5.即实际生效的还是len
	// append切片扩容
	s4 := make([]int, 0, 5)
	s4 = append(s4, 1, 2)
	fmt.Println(s4)
	// 如果切片中的数据超过了规定的容量，会自动扩容
	s4 = append(s4, 3, 4, 5, 6, 7, 8, 9)
	fmt.Println(s4)
	s5 := []int{1, 1, 1, 1, 1}
	s4 = append(s4, s5...) // 解构
	fmt.Println(s4)
	fmt.Println("\n------")
	/*
		通过数组创建切片
		从已有的数组上，直接创建切片，该切片的底层数组就是当前的数组
		长度是从start到end切割的数据量，但是容量从start到数组的末尾
	*/
	arr5 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	ss1 := arr5[:5]
	ss2 := arr5[:]
	fmt.Println(ss1)
	fmt.Println(ss2)
	// 变
	arr5[0] = 100
	ss2[1] = 200
	fmt.Println(arr5)
	fmt.Println(ss1)
	// 不变
	ss1 = append(ss1, 1, 1, 1, 1, 1, 1, 1)
	ss1[3] = 300
	fmt.Println(ss1)
	fmt.Println(arr5)
	fmt.Println("\n------")
	// 切片是引用类型
	// -- 数组是值类型
	arr6 := [4]int{1, 2, 3, 4}
	arr7 := arr6
	fmt.Println(arr6, arr7)
	arr7[0] = 100
	fmt.Println(arr6, arr7)
	// -- 切片是引用类型
	arr66 := []int{1, 2, 3, 4}
	arr77 := arr66
	fmt.Println(arr66, arr77)
	arr66[0] = 200
	fmt.Println(arr66, arr77)
	fmt.Println("\n------")
	// -- 切片实现深拷贝
	arr666 := []int{1, 2, 3, 4}
	arr777 := []int{4, 5, 6}
	fmt.Println(arr666, arr777)
	copy(arr777, arr666)
	fmt.Println(arr666, arr777)
}

func testArr() {
	// 不确定数组有多大
	arr := [...]string{"sali1", "sali2", "sali3"}
	fmt.Println(len(arr))
	fmt.Println(cap(arr))
	// 指定位置赋值
	arr4 := [5]int{1: 100, 4: 200}
	fmt.Println(arr4)
	// 数组是值传递类型
	arr1 := [3]int{1, 2, 3}
	arr2 := arr1
	arr2[0] = 100
	fmt.Println(arr1)
	fmt.Println(arr2)
	fmt.Println("\n------")
	// 多维数组
	arr3 := [3][4]int{
		{1, 2, 3, 4},
		{5, 6, 7, 8},
		{9, 10, 11, 12}}

	for i, v := range arr3 {
		fmt.Println(i, v)
		for _, v2 := range v {
			fmt.Println(v2)
		}
	}

	fmt.Println("\n-----------------")
}
